
let common = `

varying vec2 v_tex_pos;
uniform sampler2D u_particles;
uniform sampler2D u_wind;
uniform vec2 u_wind_min;
uniform vec2 u_wind_max;
uniform float u_rand_seed;
uniform float u_speed_factor;
uniform float u_drop_rate;
uniform float u_drop_rate_bump;
uniform float u_spherize;


uniform float u_palScale;
uniform float u_palBias;

uniform vec3 u_palA;
uniform vec3 u_palB;
uniform vec3 u_palC;
uniform vec3 u_palD;
uniform vec3 u_palBoost;

// cosine based palette, 4 vec3 params
vec3 palette( in float t )
{
    return u_palA + u_palB*cos( 6.283185*(u_palC*t+u_palD) );
}



uniform sampler2D particleStateTarget0;
uniform sampler2D particleStateTarget1;

varying vec3 p_color;

// pseudo-random generator
const vec3 rand_constants = vec3(12.9898, 78.233, 4375.85453);
float rrand(const vec2 co) {
    float t = dot(rand_constants.xy, co);
    return fract(sin(t) * (rand_constants.z + t));
}

// wind speed lookup; use manual bilinear filtering based on 4 adjacent pixels for smooth interpolation
vec2 lookup_wind(const vec2 uv) {

     //return texture2D(u_wind, uv).rg; // lower-res hardware filtering

    vec2 fc = uv*vec2(textureSize(u_wind,0));
    vec2 f = fract(fc);
    ivec2 ic = ivec2(fc);
    vec2 tl = texelFetch(u_wind, ic,0).rg;
    vec2 tr = texelFetch(u_wind, ic + ivec2(1, 0),0).rg;
    vec2 bl = texelFetch(u_wind, ic + ivec2(0, 1),0).rg;
    vec2 br = texelFetch(u_wind, ic + ivec2(1, 1),0).rg;
    
    return mix(mix(tl, tr, f.x), mix(bl, br, f.x), f.y);

}

vec2 computeMotion(vec2 pos,out float speed_t){
    vec2 velocity = mix(u_wind_min, u_wind_max, lookup_wind(pos));
    speed_t = length(velocity) / length(u_wind_max);
    
    // take EPSG:4236 distortion into account for calculating where the particle moved
    float distortion = cos(radians(pos.y * 180.0 - 90.0));
    
    distortion = max(.001,abs(distortion));
    
    vec2 offset = vec2(velocity.x / distortion, -velocity.y) * 0.0001 * u_speed_factor;
    return offset;
}    

vec3 toSphere(inout vec3 transformed){

    float tx = (transformed.x * radians(360.))-radians(90.);
    float ty = transformed.y * radians(180.);
    float sx = sin(tx);
    float cx = cos(tx);
    float sy = sin(ty);
    float cy = cos(ty);
    vec3 psphere = vec3(-cx*sy,-cy,sx*sy);

    vec3 pflat = (vec3(transformed.x*2.,transformed.yz)-vec3(1.,.5,0.))*2.;

   return mix(pflat,psphere,u_spherize);
}

//#define USE_FLOAT

#ifndef USE_FLOAT
vec4 p_encode(vec2 pos){
    return vec4(
        fract(pos * 255.0),
        floor(pos * 255.0) / 255.0);
}
vec2 p_decode(vec4 color){
    return vec2(
        color.r / 255.0 + color.b,
        color.g / 255.0 + color.a); // decode particle position from pixel RGBA
}
#else
vec4 p_encode(vec2 pos){
    return vec4(pos,0.,0.);
}
vec2 p_decode(vec4 color){
    return color.rg; // decode particle position from pixel RGBA
}
#endif


`

const updatePosition=`
precision highp float;

${common}

void main() {
    vec4 color = texture2D(u_particles, v_tex_pos);
    
    vec2 pos = p_decode(color);

    float speed_t;
    vec2 offset = computeMotion(pos,speed_t);

    // update particle position, wrapping around the date line
    pos = fract(1.0 + pos + offset);
    
    // a random seed to use for the particle drop
    vec2 seed = (pos + v_tex_pos) * u_rand_seed;
    
    // drop rate is a chance a particle will restart at random position, to avoid degeneration
    float drop_rate = u_drop_rate + speed_t * u_drop_rate_bump;
    float drop = step(1.0 - drop_rate, rrand(seed));
    
    vec2 random_pos = vec2(
        rrand(seed + 1.3),
        rrand(seed + 2.1));
        
    pos = mix(pos, random_pos, drop);
    
    // encode the new particle position back into RGBA
    gl_FragColor = p_encode(pos);
}`

const quadVert =
    `
precision highp float;

varying vec2 v_tex_pos;

void main() {
    v_tex_pos = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`

const streakVertex = `
int p_res = textureSize(particleStateTarget0,0).x;
int p_index = gl_InstanceID;

ivec2 p_coord=ivec2(p_index%p_res,p_index/p_res);
vec4 psamp0 = texelFetch(particleStateTarget0,p_coord,0);
vec2 pos0=p_decode(psamp0);
vec3 transformed0 = vec3(pos0,0.); 



//vec4 psamp = texelFetch(particleStateTarget1,p_coord,0);
//vec2 pos=p_decode(psamp);
//vec3 transformed = vec3(pos,0.);

float speed_t;
vec2 offset = computeMotion(pos0,speed_t);
vec3 transformed = vec3(pos0 + offset,0.);

p_color = vec3(0.);
if((gl_VertexID&1)==1){
    vec3 delta = transformed0-transformed;
    float speed = length(delta);
    if(speed<.002)
    {
        float t = speed*10000.;// / u_speed_factor;
        p_color = palette(u_palBias + (t*(1.-u_palScale))) + u_palBoost;
    
        //p_color = (normalize(delta)+1.)*.5;
        transformed = transformed - (delta*10.);
    }
}

transformed = toSphere(transformed);

`

export {updatePosition,quadVert,streakVertex,common}
